home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 2.0 / Internet Publisher's Toolbox.iso / internet / ntserver / wtsource / irfileio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-08  |  21.5 KB  |  823 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  9.  
  10.  
  11. /* Change log:
  12.  * $Log: irfileio.c,v $
  13.  * Revision 1.1  1993/02/16  15:05:35  freewais
  14.  * Initial revision
  15.  *
  16.  * Revision 1.12  92/04/12  17:30:21  jonathan
  17.  * Fixed WriteString to quote backslash as well as double-quotes.  Thanks to
  18.  * dxl0243@hertz.njit.edu (Dong Liu).
  19.  * 
  20.  * Revision 1.11  92/03/06  10:57:16  jonathan
  21.  * removed extraneous ; after function WriteTM.
  22.  * 
  23.  * Revision 1.10  92/03/04  19:20:33  jonathan
  24.  * Made SkipObject return EOF if at end of file.
  25.  * 
  26.  * Revision 1.9  92/02/16  21:08:37  jonathan
  27.  * Changed a few more char ch to long ch (for return value of fgetc).
  28.  * 
  29.  * Revision 1.8  92/02/12  13:24:13  jonathan
  30.  * Added "$Log" so RCS will put the log message in the header
  31.  * 
  32. */
  33.  
  34. /********************************************************
  35.  *  Writing and reading structures to files.            *
  36.  *                                                      *
  37.  *  These use the Lisp printer format with the          *
  38.  *  lisp naming conventions.  You ask: "Why would       *
  39.  *  you want to use that?".  Well, we need an           *
  40.  *  easily readable data syntax that can handle         *
  41.  *  a large number of different data types.             *
  42.  *  Further, we need it to be tagged so that            *
  43.  *  run time tagged languages can read it and           *
  44.  *  it is flexible.  We need one that supports          *
  45.  *  optional fields so that the format can              *
  46.  *  grow backcompatibly.  And (the kicker),             *
  47.  *  it must be read from many languages since           *
  48.  *  user interfaces may be written in anything          *
  49.  *  from smalltalk to hypercard.                        *
  50.  *                                                      *
  51.  *  -brewster 5/10/90                                   *
  52.  ********************************************************/
  53.  
  54. #include <string.h>
  55. #include <ctype.h>
  56. #include "irfileio.h"
  57. #include "cutil.h"
  58.  
  59. #define INDENT_SPACES 2
  60. #define MAX_INDENT 40
  61. static long indent_level;  /* this is the number of indent levels */
  62.  
  63.  
  64. /**********************/
  65. /*  WRITING TO FILES  */
  66. /**********************/
  67.  
  68.  
  69. static void indent _AP((FILE* file));
  70.  
  71. static void indent(file)
  72. FILE* file;
  73. /* indent the right number of spaces.  make sure that indent_level is 
  74.  * non-negative, and that it does not indent too much
  75.  */
  76. {
  77.   long i;
  78.   for(i = 0; i <= MIN(MAX_INDENT, MAX(0L, indent_level * INDENT_SPACES)); i++){
  79.     putc(' ', file);
  80.   }
  81. }
  82.  
  83. long WriteStartOfList(file)
  84. FILE* file;
  85. {
  86.   indent_level++;
  87.   return(fprintf(file, " ( "));
  88. }
  89.  
  90. long WriteEndOfList(file)
  91. FILE* file;
  92. {
  93.   indent_level--;
  94.   return(fprintf(file, " ) "));
  95. }
  96.  
  97. long WriteStartOfStruct(name,file)
  98. char* name;
  99. FILE* file;
  100. {
  101.   indent_level++;
  102.   return(fprintf(file, " (:%s ", name));
  103. }
  104.  
  105. long WriteEndOfStruct(file)
  106. FILE* file;
  107. {
  108.   indent_level--;
  109.   return(fprintf(file, " ) "));
  110. }
  111.  
  112. long WriteSymbol(name,file)
  113. char* name;
  114. FILE* file;
  115. {
  116.   return(fprintf(file, " %s ", name));
  117. }
  118.  
  119. long WriteNewline(file)
  120. FILE* file;
  121. {
  122.   long return_value = fprintf(file, "\n");
  123.   indent(file);
  124.   return(return_value);
  125. }
  126.  
  127. long WriteLong(number,file)
  128. long number;
  129. FILE* file;
  130. {
  131.   return(fprintf(file, " %ld ", number));  
  132. }
  133.  
  134. long WriteDouble(number,file)
  135. double number;
  136. FILE* file;
  137. {
  138.   return(fprintf(file, " %f ", number));
  139. }
  140.  
  141. long WriteString(string,file)
  142. char* string;
  143. FILE* file;
  144. {
  145.   long i;
  146.   putc('\"', file);
  147. #ifdef WIN32
  148.   for(i = 0; i < (long)strlen(string); i++){
  149. #else
  150.   for(i = 0; i < strlen(string); i++){
  151. #endif
  152.     if(string[i] == '\\' || string[i] == '\"')
  153.       putc('\\', file);         /* quote the string quotes going into the file */
  154.     putc(string[i], file);
  155.   }
  156.   putc('\"', file);
  157.   return(1);
  158. }
  159.  
  160. long WriteAny(value,file)
  161. any* value;
  162. FILE* file;
  163. {
  164.   WriteStartOfStruct("any", file);
  165.   WriteSymbol(":size", file); WriteLong(value->size, file);
  166.   WriteSymbol(":bytes", file);
  167.   Write8BitArray(value->size, value->bytes, file);
  168.   return(WriteEndOfStruct(file));
  169. }
  170.  
  171. long Write8BitArray(length,array,file)
  172. long length;
  173. char* array;
  174. FILE* file;
  175. {
  176.   long i;
  177.   fprintf(file, " #( ");
  178.   for(i=0; i<length; i++){
  179.     WriteLong((long)array[i], file);
  180.   }
  181.   return(fprintf(file, " ) "));
  182. }
  183.  
  184. /* Writes a time object to a file */
  185. long WriteTM(atime,file)
  186. struct tm* atime;
  187. FILE* file;
  188. {
  189.   WriteStartOfStruct("tm", file);
  190.   WriteSymbol(":tm-sec", file); WriteLong(atime->tm_sec, file);
  191.   WriteSymbol(":tm-min", file); WriteLong(atime->tm_min, file);
  192.   WriteSymbol(":tm-hour", file); WriteLong(atime->tm_hour, file);
  193.   WriteSymbol(":tm-mday", file); WriteLong(atime->tm_mday, file);
  194.   WriteSymbol(":tm-mon", file); WriteLong(atime->tm_mon, file);
  195.   WriteNewline(file);
  196.   WriteSymbol(":tm-year", file); WriteLong(atime->tm_year, file);
  197.   WriteSymbol(":tm-wday", file); WriteLong(atime->tm_wday, file);
  198.   WriteNewline(file);
  199.   WriteSymbol(":tm-yday", file); WriteLong(atime->tm_yday, file);
  200.   WriteSymbol(":tm-isdst", file); WriteLong(atime->tm_isdst, file);
  201.   WriteEndOfStruct(file);
  202.   return(WriteNewline(file));
  203. }
  204.  
  205. Boolean  
  206. writeAbsoluteTime(atime,file)
  207. struct tm* atime;
  208. FILE* file;
  209. {
  210.   WriteStartOfStruct("absolute-time",file);
  211.   WriteNewline(file);
  212.   WriteSymbol(":year",file); WriteLong((long)atime->tm_year,file);
  213.   WriteNewline(file);
  214.   WriteSymbol(":month",file); WriteLong((long)atime->tm_mon,file);
  215.   WriteNewline(file);
  216.   WriteSymbol(":mday",file); WriteLong((long)atime->tm_mday,file);
  217.   WriteNewline(file);
  218.   WriteSymbol(":hour",file); WriteLong((long)atime->tm_hour,file);
  219.   WriteNewline(file);
  220.   WriteSymbol(":minute",file); WriteLong((long)atime->tm_min,file);
  221.   WriteNewline(file);
  222.   WriteSymbol(":second",file); WriteLong((long)atime->tm_sec,file);
  223.   WriteNewline(file);
  224.   return(WriteEndOfStruct(file));
  225. }
  226.  
  227.  
  228.  
  229.  
  230. /************************/
  231. /*  READING FROM FILES  */
  232. /************************/
  233.  
  234.  
  235. /* these are states of the parser */
  236. #define BEFORE 1
  237. #define DURING 2
  238. #define HASH 3
  239. #define S 4
  240. #define QUOTE 5
  241.  
  242. /* returns TRUE if it hits an '(' before hitting any non whitespace.
  243.    It has an added hack to detect NIL: it looks to make sure that it is nil,
  244.    and then ungetc's a \) on the stream so that the end-checkers will catch it.
  245.    Quack. */
  246. Boolean ReadStartOfList(file)
  247. FILE* file;
  248. {
  249.   long ch;
  250.   while(TRUE){
  251.     ch = getc(file);
  252.     if(ch == '(') 
  253.       return(TRUE);
  254.     if(!isspace(ch)){
  255.       /* check for NIL */
  256.       if(ch == 'N' || ch == 'n'){
  257.         ch = getc(file);
  258.         if(ch == 'I' || ch == 'i'){
  259.           ch = getc(file);
  260.           if(ch == 'L' || ch == 'l'){
  261.             ungetc(')', file);
  262.             return(TRUE);
  263.           }
  264.         }
  265.       }
  266.       return(FALSE); /* not NIL */
  267.     }
  268.   }
  269. }
  270.  
  271.  
  272. /* returns TRUE if it hits an ')' before hitting any non whitespace*/
  273. Boolean ReadEndOfList(file)
  274. FILE* file;
  275. {
  276.   long ch;
  277.   while(TRUE){
  278.     ch = getc(file);
  279.     if(ch == ')') 
  280.       return(TRUE);
  281.     if(!isspace(ch)) 
  282.       return(FALSE);
  283.   }
  284. }
  285.  
  286. #define STRING_ESC '\\'
  287.  
  288. long 
  289. SkipObject(file)
  290. FILE* file;
  291. /* read an object of unknown type out of the file.  We handle:
  292.       strings
  293.       longs, doubles, and symbols
  294.       structs, lists, and arrays
  295.    and anything composed of them (absolute time etc)
  296. */
  297. {
  298.   long ch;
  299.  
  300.   while (true)  
  301.     { ch = getc(file);
  302.       if (ch == EOF)
  303.         return (EOF); /* we are done */
  304.       else
  305.         { if (isspace(ch))
  306.             continue; /* skip this char */
  307.           else if (ch == '"') /* string */
  308.             { long escapeCount = 0;
  309.               while (true)
  310.                 { ch = getc(file);
  311.                   if (ch == EOF)
  312.                     return (EOF);
  313.                   else
  314.                     { if (ch == STRING_ESC)
  315.                         { escapeCount++;
  316.                           escapeCount = escapeCount % 2;
  317.                         }
  318.                       if (ch == '"' && escapeCount == 0)
  319.                         break; /* out of reading string */
  320.                     }
  321.                 }
  322.               break; /* we are done */
  323.             }
  324.           else if ((isdigit(ch) || ch == '-' || ch == '.') || /* number */
  325.                    (ch == ':')) /* symbol */
  326.             { while (!isspace(ch)) /* just read till there is white space */
  327.                 { ch = getc(file);
  328.                   if (ch == EOF)
  329.                     return(EOF);
  330.                 }
  331.               break; /* we are done */
  332.             }
  333.           else if ((ch == '#') || /* array */
  334.                    (ch == '(')) /* struct or list */
  335.             { long parenCount = 1;
  336.               if (ch == '#')    
  337.                 ch = getc(file); /* read in the '(' so we can think of it
  338.                                     as a list */
  339.               while (parenCount > 0)
  340.                 { ch = getc(file);
  341.                   if (ch == EOF)
  342.                     return(EOF);
  343.                   else if (ch == '"')
  344.                     { /* start of a string, it may contain parens, 
  345.                          so we will have to skip it */
  346.                       ungetc(ch,file);
  347.                       SkipObject(file);
  348.                     }
  349.                   else if (ch == '(') /* entering a new structure */    
  350.                     parenCount++;
  351.                   else if (ch == ')') /* leaving a structure */
  352.                     parenCount--;
  353.                 }
  354.               break; /* we are done */
  355.             }
  356.         }
  357.     }
  358.  
  359.   return(true);
  360. }
  361.  
  362. long ReadLong(file,answer)
  363. FILE* file;
  364. long* answer;
  365. /* reads a long int a file returns true if successful, false otherwise */
  366. {
  367.   long ch;
  368.   long state = BEFORE;
  369.   boolean isNegative = false;
  370.   long count = 0;
  371.   
  372.   *answer = 0;
  373.   
  374.   while(TRUE){
  375.     ch = getc(file);
  376.     if (ch == EOF){
  377.       break;                    /* we are done */
  378.     }
  379.     else if (isdigit(ch)){
  380.       if(state == BEFORE){
  381.         state = DURING;
  382.       }
  383.       count++;
  384.       if(count == 12){
  385.         /* then we have an error in the file, 32 bit numbers can not be more
  386.            than 10 digits long */
  387.         return(false);
  388.       }
  389.       *answer = *answer * 10 + (ch - '0');
  390.     }
  391.     else if (ch == '-') {
  392.       if (isNegative)
  393.         /* then we have an error since there should be only one - in a number */
  394.         return(false);
  395.       if (state == BEFORE) {
  396.         /* we are ok since the - must come before any digits */
  397.         isNegative = true;
  398.         state = DURING;
  399.       }
  400.       else {
  401.         ungetc(ch,file);
  402.         break;                  /* we are done */
  403.       }
  404.     }
  405.     else if(ch == ')' && (state == DURING)){
  406.       ungetc(ch, file);
  407.       return(true);             /* we are done */
  408.     }
  409.     else if(!isspace(ch)){
  410.       /* then we have an error since it should be a digit or a space */
  411.       return(false);
  412.     }
  413.     /* we do not have an digit */
  414.     else if(state == DURING){
  415.       ungetc(ch, file);
  416.       break;                    /* we are done */
  417.     }
  418.     /* otherwise we are still before the start */
  419.   }
  420.   
  421.   if (isNegative)
  422.     *answer *= -1;
  423.   return(true);
  424. }
  425.  
  426. long ReadDouble(file,answer)
  427. FILE* file;
  428. double* answer;
  429. {
  430.   /* XXX this routine needs to deal with negative numbers! */
  431.   long ch;
  432.   long state = BEFORE;
  433.   long count = 0;
  434.   long decimal_count = 0;
  435.   
  436.   *answer = 0.0;
  437.   
  438.   while(TRUE){  
  439.     ch = getc(file);
  440.     if (ch == EOF){
  441.       return(true);
  442.     }
  443.     else if (ch == '.'){
  444.       decimal_count ++;
  445.     }
  446.     else if (isdigit(ch)){
  447.       if(state == BEFORE){
  448.         state = DURING;
  449.       }
  450.       count++;
  451.       if(count == 12){
  452.         /* then we have an error in the file, 32 bit numbers can not be more
  453.            than 10 digits long */
  454.         return(false);
  455.       }
  456.       if (decimal_count == 0){
  457.         *answer = *answer * 10 + (ch - '0');
  458.       }
  459.       else{                     /* then we are in the fraction part */
  460.         double fraction = (ch - '0');
  461.         long internal_count;
  462.         for(internal_count = 0; internal_count < decimal_count; 
  463.             internal_count++){
  464.           fraction = fraction / 10.0;
  465.         }
  466.         *answer = *answer + fraction;
  467.         decimal_count++;
  468.       }
  469.     }
  470.     else if(!isspace(ch)){
  471.       /* then we have an error since it should be a digit or a space */
  472.       return(false);
  473.     }
  474.     /* we do not have an digit */
  475.     else if(state == DURING){
  476.       ungetc(ch, file);
  477.       return(true);             /* we are done */
  478.     }
  479.     /* otherwise we are still before the start */
  480.   }
  481. }
  482.  
  483. static Boolean issymbolchar _AP((long ch));
  484.  
  485. static 
  486. Boolean issymbolchar(ch)
  487. long ch;
  488. /* reads a symbol from a file and put it in the string argument.
  489.  * The string_size argument is used to make sure the string is not 
  490.  * overflowed.
  491.  */
  492. {
  493.   return(!( isspace(ch) || ch == ')' || ch == '(' || ch == EOF));
  494. }
  495.  
  496. /* reads a symbol from a file */
  497. long ReadSymbol(string,file,string_size)
  498. char* string;
  499. FILE* file;
  500. long string_size;
  501. {
  502.   long ch;
  503.   long state = BEFORE;
  504.   long position = 0;
  505.   
  506.   while(TRUE){
  507.     ch = getc(file);
  508.     if((state == BEFORE) && (ch == ')'))
  509.       return(END_OF_STRUCT_OR_LIST);
  510.     if(issymbolchar((long)ch)){ /* we are in a symbol */
  511.       if(state == BEFORE)
  512.         state = DURING;
  513. #ifdef WIN32
  514.       string[position] = (char)ch;
  515. #else
  516.       string[position] = ch;
  517. #endif
  518.       position++;
  519.       if(position >= string_size){
  520.         string[string_size - 1] = '\0';
  521.         return(FALSE);
  522.       }
  523.     }
  524.     /* we do not have an symbol character. we are done */
  525.     else if((state == DURING) || ch == EOF){
  526.       if(ch != EOF) ungetc(ch, file);
  527.       string[position] = '\0';
  528.       return(TRUE);             /* we are done */
  529.     }
  530.     /* otherwise we are still before the start of the symbol */
  531.   }
  532. }
  533.  
  534. long ReadEndOfListOrStruct(file)
  535. FILE* file;
  536. {
  537.   long ch;
  538.   while(TRUE){
  539.     ch = getc(file);
  540.     if (EOF == ch) 
  541.       return(FALSE);
  542.     else if(')' == ch) 
  543.       return(TRUE);
  544.     else if(!isspace(ch)) 
  545.       return(FALSE);
  546.   }
  547. }
  548.  
  549. /* reads a string from a file */
  550. long ReadString(string,file,string_size)
  551. char* string;
  552. FILE* file;
  553. long string_size;
  554. {
  555.   long ch;
  556.   long state = BEFORE;
  557.   long position = 0;
  558.   string[0] = '\0';  /* initialize to nothing */
  559.   
  560.   while(TRUE){
  561.     ch = getc(file);
  562.     if((state == BEFORE) && (ch == '\"'))
  563.       state = DURING;
  564.     else if (EOF == ch){
  565.       string[position] = '\0';
  566.       return(FALSE);
  567.     }
  568.     else if ((state == BEFORE) && (ch == ')'))
  569.       return(END_OF_STRUCT_OR_LIST);
  570.     else if ((state == DURING) && (ch == '\\'))
  571.       state = QUOTE; /* do nothing */
  572.     else if ((state == DURING) && (ch == '"')){ 
  573.       string[position] = '\0';
  574.       return(TRUE);
  575.     }
  576.     else if ((state == QUOTE) || (state == DURING)){
  577.                         if(state == QUOTE)
  578.                                 state = DURING;
  579. #ifdef WIN32
  580.                         string[position] = (char)ch;
  581. #else
  582.                         string[position] = ch;
  583. #endif
  584.                         position++;
  585.                         if(position >= string_size){
  586.                                 string[string_size - 1] = '\0';
  587.                                 return(FALSE);
  588.                         }
  589.                 }
  590.                 /* otherwise we are still before the start of the string */
  591.         }
  592. }
  593.  
  594. /* returns TRUE if it is the start of a struct
  595.  * returns END_OF_STRUCT_OR_LIST if it is a ')'
  596.  * returns FALSE if it is something unexpected
  597.  */
  598. long ReadStartOfStruct(name,file)
  599. char* name;
  600. FILE* file;
  601. {
  602.   long ch;
  603.   long state = BEFORE;
  604.         
  605.   name[0] = '\0';
  606.         
  607.   while(TRUE){
  608.     ch = getc(file);
  609.     if((state == BEFORE) && (ch == '#'))
  610.       state = HASH;
  611.     if((state == BEFORE) && (ch == '('))
  612.       state = DURING;
  613.     else if((state == BEFORE) && (ch == ')'))
  614.       return(END_OF_STRUCT_OR_LIST);
  615.     else if((state == BEFORE) && !isspace(ch))
  616.       return(FALSE);            /* we have a problem */
  617.     else if(state == HASH){
  618.       if (ch == 's')
  619.         state = S;
  620.       else{
  621.         fprintf(stderr,"Expected an 's' but got an %c\n", ch);
  622.         return(FALSE);
  623.       }
  624.     }
  625.     else if(state == S){
  626.       if (ch == '(')
  627.         state = DURING;
  628.       else{
  629.         fprintf(stderr,"Expected an '(' but got an an %c\n",ch);
  630.         return(FALSE);
  631.       }
  632.     }
  633.     else if(state == DURING){
  634.       return(ReadSymbol(name, file, MAX_SYMBOL_SIZE));
  635.     }
  636.   }
  637. }
  638.  
  639. /* returns TRUE if it is the right start of a struct,
  640.  * returns END_OF_STRUCT_OR_LIST if it is the end of a list,
  641.  * returns FALSE if it is something weird
  642.  */
  643. long CheckStartOfStruct(name,file)
  644. char* name;
  645. FILE* file;
  646. {
  647.   char temp_string[MAX_SYMBOL_SIZE];
  648.   long result = ReadStartOfStruct(temp_string, file);
  649.   if(result == END_OF_STRUCT_OR_LIST)
  650.     return(END_OF_STRUCT_OR_LIST);
  651.   else if(result == FALSE)
  652.     return(FALSE);
  653.   else if(0 == strcmp(temp_string, name))
  654.     return(TRUE);
  655.   else 
  656.     return(FALSE);
  657. }
  658.  
  659. /* reads an any.  an any with no bytes allocated.  The right number of bytes
  660.  * will be malloc'ed while reading
  661.  */
  662. long ReadAny(destination,file)
  663. any* destination;
  664. FILE* file;
  665. {
  666.   char temp_string[MAX_SYMBOL_SIZE];
  667.         
  668.   destination->size = 0; /* initialize so that if an error happens 
  669.                             it does not blow up */
  670.   if(FALSE == CheckStartOfStruct("any", file)){
  671.     fprintf(stderr,"An 'any' structure was not read from the disk");
  672.     return(FALSE);
  673.   }
  674.         
  675.   while(TRUE){
  676.     long check_result;
  677.     check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
  678.     if(FALSE == check_result) 
  679.       return(FALSE);
  680.     if(END_OF_STRUCT_OR_LIST == check_result) 
  681.       return(TRUE);
  682.                 
  683.     if(0 == strcmp(temp_string, ":size")) {
  684.       long      size;
  685.       ReadLong(file,&size);
  686.       destination->size = (unsigned long)size;
  687.     }
  688.     else if(0 == strcmp(temp_string, ":bytes")){
  689.       long result;
  690.       /* the size must have been read in by now */
  691.       destination->bytes = (char*)s_malloc(destination->size);
  692.       if(NULL == destination->bytes){
  693.         fprintf(stderr,
  694.                 "Error on reading file. Malloc ran out of memory in an ANY");
  695.         return(FALSE);
  696.       }
  697.       result = Read8BitArray(destination->bytes, file, destination->size);
  698.       if(FALSE == result)
  699.         return(FALSE);
  700.     }
  701.     else{
  702.       fprintf(stderr,"Unknown keyword for ANY %s\n", temp_string);
  703.       return(FALSE);
  704.     }
  705.   }
  706. }
  707.  
  708. /* this does not need the length, but it will probably know it in all cases */
  709. long Read8BitArray(destination,file,length)
  710. char* destination;
  711. FILE* file;
  712. long length;
  713. {
  714.   /* arrays start with #( */
  715.   long ch;
  716.   long state = BEFORE;
  717.   while(TRUE){
  718.     ch = getc(file);
  719.     if((state == BEFORE) && ((ch == '#') || (ch == '('))) {
  720.       if (ch == '(') state = DURING;
  721.       else state = HASH;
  722.     }
  723.     else if((state == BEFORE) && !isspace(ch)){
  724.       fprintf(stderr,"error in reading array.  Expected # and got %c", ch);
  725.       return(FALSE);
  726.     }
  727.     else if(state == HASH){
  728.       if (ch == '(')
  729.         state = DURING;
  730.       else{
  731.         fprintf(stderr,"Expected an '(' but got an %c\n", ch);
  732.         return(FALSE);
  733.       }
  734.     }
  735.     else if(state == DURING){
  736.       long i;
  737.       ungetc(ch, file);
  738.       for(i = 0; i < length; i++){
  739.         long value;
  740.         if(ReadLong(file,&value) == false){ /* then it error'ed */
  741.           fprintf(stderr,"Error in reading a number from the file.");
  742.           return(FALSE);
  743.         }
  744.         if(value > 255){        /* then we have read a non-char */
  745.           fprintf(stderr,"Error in reading file.  Expected a byte in an ANY, but got %ld", value);
  746.           return(FALSE);
  747.         }
  748.         destination[i] = (char)value;
  749.       }
  750.       if(FALSE == ReadEndOfListOrStruct(file)){
  751.         fprintf(stderr,"array was wrong length");
  752.         return(FALSE);
  753.       }
  754.       return(TRUE);
  755.     }
  756.   }
  757. }
  758.                         
  759.  
  760. Boolean
  761. readAbsoluteTime(atime,file)
  762. struct tm* atime;
  763. FILE* file;
  764. {
  765.   if (CheckStartOfStruct("absolute-time",file) == FALSE)
  766.     return(false);
  767.                   
  768.   while (true)
  769.     { long result;
  770.       long val;
  771.       char temp_string[MAX_SYMBOL_SIZE + 1];
  772.      
  773.       result = ReadSymbol(temp_string,file,MAX_SYMBOL_SIZE);
  774.      
  775.       if (result == END_OF_STRUCT_OR_LIST)
  776.         break;
  777.       else if (result == false)
  778.         return(false);
  779.                        
  780.       if (strcmp(temp_string,":second") == 0)
  781.         { if (ReadLong(file,&val) == false)
  782.             return(false);
  783.           atime->tm_sec = val;
  784.         }
  785.  
  786.       else if (strcmp(temp_string,":minute") == 0)
  787.         { if (ReadLong(file,&val) == false)
  788.             return(false);
  789.           atime->tm_min = val;
  790.         }
  791.  
  792.       else if (strcmp(temp_string,":hour") == 0)
  793.         { if (ReadLong(file,&val) == false)
  794.             return(false);
  795.           atime->tm_hour = val;
  796.         }
  797.  
  798.       else if (strcmp(temp_string,":mday") == 0)
  799.         { if (ReadLong(file,&val) == false)
  800.             return(false);
  801.           atime->tm_mday = val;
  802.         }
  803.  
  804.       else if (strcmp(temp_string,":month") == 0)
  805.         { if (ReadLong(file,&val) == false)
  806.             return(false);
  807.           atime->tm_mon = val;
  808.         }
  809.  
  810.       else if (strcmp(temp_string,":year") == 0)
  811.         { if (ReadLong(file,&val) == false)
  812.             return(false);
  813.           atime->tm_year = val;
  814.         }
  815.       
  816.       else
  817.         SkipObject(file);
  818.  
  819.     }
  820.  
  821.   return(true);
  822. }
  823.